package cn.jiangjiesheng.bootstrap.commons.response;

import cn.hutool.core.bean.BeanUtil;
import cn.jiangjiesheng.bootstrap.commons.annotation.IgnoreResponseWrapper;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import cn.jiangjiesheng.commons.annotation.ResponseJson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 接口异常捕获
 * <p>
 * Created by dev@jiangjiesheng.cn on 2021/8/25  <br/>
 *
 * @author jerrylau
 */
@RestControllerAdvice(basePackages = {"cn.jiangjiesheng", "cn.jiangjiesheng"})
@Slf4j
public class SafetyResponseBodyAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    /**
     * 重写返回结果
     * 1. 返回的result中，如果是列表必须放在list字段下
     * 2. result是一个object键值对
     *
     * @param o
     * @param methodParameter
     * @param mediaType
     * @param aClass
     * @param request
     * @param response
     * @return
     */
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType,
                                  Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest request,
                                  ServerHttpResponse response) {
        if (Objects.nonNull(methodParameter.getMethodAnnotation(IgnoreResponseWrapper.class))) {
            return o;
        }
        // 如果业务端直接返回了JSON字符串【不处理的话字符串会被json转义】
        if (Objects.nonNull(o) && o instanceof String && ((String) o).startsWith("{")
                && ((String) o).endsWith("}")) {
            response.getHeaders().add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
            if (((String) o).contains("openapi")) {
                return JSON.parseObject((String) o);
            }
            // 如果返回的是一个完整的json
            int indexOfSuccessString = o.toString().indexOf("success");
            if (indexOfSuccessString > 0 && indexOfSuccessString < 15) {
                o = JSON.parseObject(o.toString()).get("result");
            }
            // 如果是没有规范包装的json
            o = JSON.parseObject(o.toString());
        }
        try {
            ResponseWrapper<Object> returning;
            // 考虑空指针异常
            if (Objects.isNull(o)) return ResponseWrapper.builder().result("").success(true).message("success").build();
            if (o instanceof ResponseWrapper) return o;
            // 如果直接返回如下类型，则优先返回
            if (o instanceof String || o instanceof Boolean || o instanceof Number || o instanceof Date) {
                final HashMap<Object, Object> objectHashMap = Maps.newHashMap();
                objectHashMap.put("value", o);
                final ResponseWrapper<Object> wrapper = ResponseWrapper.builder().result(objectHashMap).success(true).message("success").build();
                if (o instanceof String) return wrapper.toJson();
                return wrapper;
            }
            // 获取字段
            List<String> fields = Lists.newArrayList();
            if (o instanceof Map) {
                fields.addAll(((Map) o).keySet());
            } else {
                fields = Arrays.stream(o.getClass().getDeclaredFields()).map(Field::getName).collect(Collectors.toList());
            }
            // 自定义result结构体的兼容
            if (fields.containsAll(Arrays.asList("result", "success")) || fields.containsAll(Arrays.asList("message", "result"))) {
                return o;
            }
            // mybatis-plus兼容性
            if (fields.containsAll(Arrays.asList("records", "size"))) {
                final Map<String, Object> map = BeanUtil.beanToMap(o);
                map.put("list", map.get("records"));
                map.remove("records");
                returning = ResponseWrapper.builder().result(map).success(true).message("success").build();
            } else if (Objects.nonNull(methodParameter.getMethodAnnotation(ResponseJson.class))) {
                ResponseJson annotation = methodParameter.getMethodAnnotation(ResponseJson.class);
                String value = annotation.value();
                if (StringUtils.isNotBlank(value)) {
                    final HashMap<Object, Object> hashMap = Maps.newHashMap();
                    hashMap.put(value, o);
                    returning = ResponseWrapper.builder().result(hashMap).success(true).build();
                } else {
                    returning = ResponseWrapper.builder().success(true).result(o).build();
                }
            } else if (o instanceof List) {
                // 返回List
                Map<String, Object> map = Maps.newHashMap();
                map.put("list", o);
                returning = ResponseWrapper.builder().result(map).success(true).message("success").build();
            } else {
                // 如果不是list也不是page，则返回对象
                returning = ResponseWrapper.builder().result(o).success(true).message("success").build();
            }
            log.debug("rest returning data is {}", returning);
            if (mediaType.includes(MediaType.TEXT_HTML)) {
                return JSON.toJSONString(returning);
            }
            return returning;
        } catch (Exception e) {
            log.error("请求错误：{}\n{}", e.getMessage(), e.getStackTrace());
            e.printStackTrace();
            return ResponseWrapper.builder().result(e.getMessage()).success(false).message("failed").build();
        }
    }
}
